# Copyright (c) 2019 Sebastian Gniazdowski
# License MIT

emulate -RL zsh
setopt extendedglob warncreateglobal typesetsilent noshortloops

typeset -g za_rust_ef
za_rust_ef=( ${(k)functions} )
trap "unset -f -- \"\${(k)functions[@]:|za_rust_ef}\" &>/dev/null; unset za_rust_ef" EXIT
trap "unset -f -- \"\${(k)functions[@]:|za_rust_ef}\" &>/dev/null; unset za_rust_ef; return 1" INT

[[ "$1" = plugin ]] && \
    local type="$1" user="$2" plugin="$3" id_as="$4" dir="$5" hook="$6" || \
    local type="$1" url="$2" id_as="$3" dir="$4" hook="$5"

if [[ $OSTYPE == cygwin ]]; then
    dir=`cygpath -w $dir`
fi

local nl=$'\n'

# FUNCTION: .zinit-annex-rust-download-file-stdout [[[
# Downloads file to stdout. Supports following backend commands:
# curl, wget, lftp, lynx. Used by snippet loading.
.zinit-annex-rust-download-file-stdout() {
    local url="$1" restart="$2"

    setopt localoptions localtraps

    if (( restart )); then
        (( ${path[(I)/usr/local/bin]} )) || \
            { 
                path+=( "/usr/local/bin" );
                trap "path[-1]=()" EXIT
            }
    
        if (( ${+commands[curl]} )) then
            command curl -fsSL "$url" || return 1
        elif (( ${+commands[wget]} )); then
            command wget -q "$url" -O - || return 1
        elif (( ${+commands[lftp]} )); then
            command lftp -c "cat $url" || return 1
        elif (( ${+commands[lynx]} )) then
            command lynx -source "$url" || return 1
        else
            return 2
        fi
    else
        if type curl 2>/dev/null 1>&2; then
            command curl -fsSL "$url" || return 1
        elif type wget 2>/dev/null 1>&2; then
            command wget -q "$url" -O - || return 1
        elif type lftp 2>/dev/null 1>&2; then
            command lftp -c "cat $url" || return 1
        else
            .zinit-annex-rust-download-file-stdout "$url" "1"
            return $?
        fi
    fi

    return 0
} # ]]]

if (( ${+ICE[rustup]} )) {
    if [[ $hook = *atclone-<-> ]] {
        (
            builtin cd -q "$dir" || {
                print -P -- "%F{38}rust annex: %F{198}An internal error, please report at: %F{220}https://github.com/zdharma-continuum/zinit-annex-rust/issues%F{198}%f"
                return 1
            }
            command mkdir -p bin rustup
            .zinit-annex-rust-download-file-stdout 'https://sh.rustup.rs' 0 >! bin/rustup-init || \
            {
                .zinit-annex-rust-download-file-stdout 'https://sh.rustup.rs' 1 >! bin/rustup-init || \
                {
                    print -P -- "%F{38}rust annex: %F{198}Couldn't download the %F{220}rustup.rs%F{198} installer%f"
                    return 0
                }
            }
            command chmod +x bin/rustup-init
            local -x CARGO_HOME="$dir" RUSTUP_HOME="$dir/rustup" 
            if (( !OPTS[opt_-q,--quiet] )) {
                print -P -- "%F{38}rust annex: %F{154}Running the rustup installer...%f"
                bin/rustup-init \
                    -y \
                    --no-modify-path \
                    --component cargo clippy rustc rust-fmt rust-std \
                    --default-toolchain nightly \
                    --profile minimal \
                |& command egrep '(installing|installed)'
            } else {
                bin/rustup-init \
                    -y \
                    --no-modify-path \
                    --component cargo clippy rustc rust-fmt rust-std \
                    --default-toolchain nightly \
                    --profile minimal \
                &> /dev/null
            }
        ) || \
            return 0
    } else {
        (
            builtin cd -q "$dir" || {
                print -P -- "%F{38}rust annex: %F{198}An internal error, please report at: %F{220}https://github.com/zdharma-continuum/zinit-annex-rust/issues%F{198}%f"
                return 1
            }
            local -x CARGO_HOME="$dir" RUSTUP_HOME="$dir/rustup" PATH="$dir/bin:$PATH"
            if (( !OPTS[opt_-q,--quiet] )) {
                print -P -- "%F{38}rust annex: %F{154}Running \`rustup update'...%f"
                command rustup update |& command egrep -i '(error|warning|installing|info: latest update )'
            } else {
                command rustup update &> /dev/null
            }
        )
    }
}

if [[ -n "${ICE[cargo]}" ]] {
    local -a cargo_defs bin_pkg_dst tmpsdst cargos
    cargo_defs=( "${(s.;.)ICE[cargo]}" )

    local cargo

    for cargo ( $cargo_defs ) {
        bin_pkg_dst=( ${(@s.->.)cargo} )
        tmpsdst=( ${(@s.<-.)bin_pkg_dst[1]} )
        if (( ${#tmpsdst} > 1 )); then
            bin_pkg_dst=( "${tmpsdst[1]}" "${tmpsdst[2]}" "${bin_pkg_dst[2]:-${tmpdist[2]#\!}}" )
        else
            bin_pkg_dst=( "${tmpsdst[1]#\!}" "${tmpsdst[1]}" "${bin_pkg_dst[2]:-${bin_pkg_dst[1]#\!}}" )
        fi
        bin_pkg_dst=( "${bin_pkg_dst[@]//((#s)[[:space:]]##|[[:space:]]##(#e))/}" )
        bin_pkg_dst[2]=${bin_pkg_dst[2]#\!}
        bin_pkg_dst[1]=${bin_pkg_dst[1]##[a-zA-Z]##:}
        bin_pkg_dst[2]=${bin_pkg_dst[2]##[a-zA-Z]##:}
        bin_pkg_dst[3]=${bin_pkg_dst[3]##[a-zA-Z]##:}

        cargos+=( ${bin_pkg_dst[2]} )
    }

    (( ${#cargos} )) && {
        if [[ "$hook" = *atclone-<-> ]]; then
            print -P -- "%F{38}rust annex: %F{154}Installing the requested crates...%f"
            if (( ${+ICE[rustup]} )) {
                local -x CARGO_HOME="$dir" RUSTUP_HOME="$dir/rustup" PATH="$dir/bin:$PATH"
                command $dir/bin/cargo install --force --root "$dir" "${cargos[@]}"
            } else {
                cargo install --force --root "$dir" "${cargos[@]}"
            }
        elif [[ "$hook" = *atpull-<-> ]]; then
            if (( !OPTS[opt_-q,--quiet] )) {
                print -P -- "%F{38}rust annex: %F{154}Updating the installed crates...%f"
            }
            local toml_dir
            local -a tomls
            tomls=( "$dir"/**/Cargo.toml(N.) )
            for toml_dir ( ${tomls:h} ) {
                (
                    builtin cd -q "$toml_dir" && {
                        if (( ${+ICE[rustup]} )) {
                            local -x CARGO_HOME="$dir" RUSTUP_HOME="$dir/rustup" PATH="$dir/bin:$PATH"
                            command $dir/bin/cargo update
                            command $dir/bin/cargo build
                        } else {
                            cargo update
                            cargo build
                        }
                    }
                )
            }
        fi
    }
}

if [[ -n "${ICE[cargo]}" ]] {
    local -a cargos bin_pkg_dst
    cargos=( "${(s.;.)ICE[cargo]}" )

    local cargo

    for cargo ( $cargos ) {
        integer set_rust_home_vars=0 \
                set_gem_home=0 set_node_path=0 set_cwd=0 \
                use_all_null=0 use_err_null=0 use_out_null=0

        bin_pkg_dst=( ${(@s.->.)cargo} )
        bin_pkg_dst=( "${bin_pkg_dst[@]//((#s)[[:space:]]##|[[:space:]]##(#e))/}" )
        tmpsdst=( ${(@s.<-.)bin_pkg_dst[1]} )
        tmpsdst=( "${tmpsdst[@]//((#s)[[:space:]]##|[[:space:]]##(#e))/}" )
        if (( ${#tmpsdst} > 1 )); then
            bin_pkg_dst=( "${tmpsdst[1]}" "${tmpsdst[2]}" "${bin_pkg_dst[2]:-${tmpdist[2]#\!}}" )
        else
            bin_pkg_dst=( "${tmpsdst[1]#\!}" "${tmpsdst[1]}" "${bin_pkg_dst[2]:-${bin_pkg_dst[1]#\!}}" )
        fi
        bin_pkg_dst=( "${bin_pkg_dst[@]//((#s)[[:space:]]##|[[:space:]]##(#e))/}" )
        if [[ ${bin_pkg_dst[2]} = \!* ]]; then
            bin_pkg_dst[2]=${bin_pkg_dst[2]#\!}
            [[ ${bin_pkg_dst[2]} = [gncNEO]#R[gncNEO]#:* ]] && set_rust_home_vars=1
            [[ ${bin_pkg_dst[2]} = [gncNEO]#g[gncNEO]#:* ]] && set_gem_home=1
            [[ ${bin_pkg_dst[2]} = [gncNEO]#n[gncNEO]#:* ]] && set_node_path=1
            [[ ${bin_pkg_dst[2]} = [gncNEO]#c[gncNEO]#:* ]] && set_cwd=1
            [[ ${bin_pkg_dst[2]} = [gncNEO]#N[gncNEO]#:* ]] && use_all_null=1
            [[ ${bin_pkg_dst[2]} = [gncNEO]#E[gncNEO]#:* ]] && use_err_null=1
            [[ ${bin_pkg_dst[2]} = [gncNEO]#O[gncNEO]#:* ]] && use_out_null=1
            bin_pkg_dst[1]=${bin_pkg_dst[1]##[a-zA-Z]##:}
            bin_pkg_dst[2]=${bin_pkg_dst[2]##[a-zA-Z]##:}
            bin_pkg_dst[3]=${bin_pkg_dst[3]##[a-zA-Z]##:}
        else
            continue
        fi


        local target_binary="${${(M)bin_pkg_dst[1]:#/*}:-$dir/bin/${bin_pkg_dst[1]}}" \
            fnam="${bin_pkg_dst[3]:-${bin_pkg_dst[1]:t}}"
        local file="$ZPFX/bin/$fnam"

        .za-rust-bin-or-src-function-body 0 \
                    "$fnam" "$target_binary" "$dir" \
                    "${${(M)set_rust_home_vars:#1}:-${+ICE[rustup]}}" \
                    "$set_gem_home" "$set_node_path" "$set_cwd" \
                    "$use_all_null" "$use_err_null" "$use_out_null"

        builtin print -r -- "#!/usr/bin/env zsh$nl$nl$REPLY$nl$nl$fnam \"\$@\"" \
            >! "$file"
        command chmod +x "$file"

        if [[ -x $file ]]; then
            if (( !OPTS[opt_-q,--quiet] )); then
                if [[ $hook == atclone-<-> || $ZINIT[annex-multi-flag:pull-active] -ge 1 ]]; then
                    +zinit-message "{pre}rust annex: {data2}${${hook:#*atclone-<->}:+Re-}Created the {file}$fnam{data2} shim.{rst}"
                fi
            fi
        else
            print -P -- "{error}rust annex: {data2}Something went wrong creating the {file}$fnam{data2} shim.{rst}"
        fi
    }
}
# vim:ft=zsh:sw=4:sts=4:et:foldmarker=[[[,]]]
